/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include ".\packetbuilderex.h"

#include <Winsock2.h>

//---------------------------------------------------------------------------

PacketBuilderEx::PacketBuilderEx(void) : PacketBuilder()
{
	mimicInfoPack.Set(__mosRandom);
}

PacketBuilderEx::~PacketBuilderEx(void)
{
}

//---------------------------------------------------------------------------

void PacketBuilderEx::SetMimic(MimicOS mosIn)
{
	mimicInfoPack.Set(mosIn);
}

//---------------------------------------------------------------------------

int PacketBuilderEx::BuildSynOptions(BYTE* buff)
{
	DWORD dwVal;
	BYTE* bVal;
	int retVal;

	MimicOS myMimic;

	if(buff==NULL) return 0;

	myMimic = mimicInfoPack.GetMimic();

	switch(myMimic){
		case __mosWindowsXPSP2 :
		case __mosWindows2K3 :
			buff[0] = 0x02; buff[1] = 0x04; buff[2] = 0x05; buff[3] = 0xB4;		// RFC 0793 : Maximum Segment Size, length = 4
			buff[4] = 0x01;														// RFC 0793 : nop
			buff[5] = 0x01;														// RFC 0793 : nop
			buff[6] = 0x04; buff[7] = 0x02;										// RFC 2018 : Sack-Permitted Option, length = 2

			retVal = 8;
			break;

		case __mosLinux_2_4:
			dwVal = GetTickCount();
			bVal  = (BYTE*)&dwVal;

			buff[0]  = 0x02; buff[1]  = 0x04; buff[2]  = 0x05; buff[3]  = 0xB4;	// RFC 0793 : Maximum Segment Size, length = 4

			buff[4]  = 0x04; buff[5]  = 0x02;									// RFC 2018 : Sack-Permitted Option, length = 2

			buff[6]  = 0x08;    buff[7]  = 0x0A;								// RFC 1323 : Timestamps Option, length = 10
			buff[8]  = bVal[0]; buff[9]  = bVal[1];								//		- Timestamp Value field
			buff[10] = bVal[2]; buff[11] = bVal[3];								//		- Timestamp Value field (continued)
			buff[12] = 0x00;    buff[13] = 0x00;								//		- Timestamp Echo Reply field
			buff[14] = 0x00;    buff[15] = 0x00;								//		- Timestamp Echo Reply field

			buff[16] = 0x01;													// RFC 0793 : nop

			buff[17] = 0x03; buff[18] = 0x03; buff[19] = 0x00;					// RFC 1323 : Window Scale Option, length = 3

			retVal = 20;
			break;

		case __mosLinux_2_6:
			dwVal = GetTickCount();
			bVal  = (BYTE*)&dwVal;

			buff[0]  = 0x02; buff[1]  = 0x04; buff[2]  = 0x05; buff[3]  = 0xB4;	// RFC 0793 : Maximum Segment Size, length = 4

			buff[4]  = 0x04; buff[5]  = 0x02;									// RFC 2018 : Sack-Permitted Option, length = 2

			buff[6]  = 0x08;    buff[7]  = 0x0A;								// RFC 1323 : Timestamps Option, length = 10
			buff[8]  = bVal[0]; buff[9]  = bVal[1];								//		- Timestamp Value field
			buff[10] = bVal[2]; buff[11] = bVal[3];								//		- Timestamp Value field (continued)
			buff[12] = 0x00;    buff[13] = 0x00;								//		- Timestamp Echo Reply field 
			buff[14] = 0x00;    buff[15] = 0x00;								//		- Timestamp Echo Reply field (continued)

			buff[16] = 0x01;													// RFC 0793 : nop

			buff[17] = 0x03; buff[18] = 0x03; buff[19] = 0x02;					// RFC 1323 : Window Scale Option, length = 3

			retVal = 20;
			break;

		case __mosSolaris_8:
			buff[0] = 0x01;														// RFC 0793 : nop
			buff[1] = 0x01;														// RFC 0793 : nop
			buff[2] = 0x04; buff[3] = 0x02;										// RFC 2018 : Sack-Permitted Option, length = 2
			buff[4] = 0x02; buff[5] = 0x04; buff[6] = 0x05; buff[7] = 0xB4;		// RFC 0793 : Maximum Segment Size, length = 4

			retVal = 8;
			break;

		case __mosNevada35:
			buff[0] = 0x02; buff[1] = 0x04; buff[2] = 0x05; buff[3] = 0xB4;	// RFC 0793 : Maximum Segment Size, length = 4
			buff[4] = 0x01;													// RFC 0793 : nop
			buff[5] = 0x03; buff[6] = 0x03; buff[7] = 0x00;					// RFC 1323 : Window Scale Option, length = 3
			buff[8] = 0x01;													// RFC 0793 : nop
			buff[9] = 0x01;													// RFC 0793 : nop
			buff[10] = 0x04; buff[11] = 0x02;								// RFC 2018 : Sack-Permitted Option, length = 2

			retVal = 12;
			break;

		default:
			retVal = 0;
			break;
	}

	return retVal;
}
//---------------------------------------------------------------------------

int PacketBuilderEx::BuildIcmpEchoDataBuffer(BYTE* dataIn)
{
	__time64_t lTime;
	DWORD valD;
	BYTE* bbb;
	BYTE val;
	int i;

	int retVal;

	if(dataIn==NULL) return 0;

	MimicOS myMimic;

	myMimic = mimicInfoPack.GetMimic();

	switch(myMimic){
		case __mosWindowsXPSP2 :
		case __mosWindows2K3 :
			for(i=0; i<32; i++){
				val = 0x61 + i;
				if(val>0x77)
					val -= 0x17;
				dataIn[i] = val;
			}
/*
0020   -- -- -- -- -- -- -- -- -- -- 61 62 63 64 65 66
0030   67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76
0040   77 61 62 63 64 65 66 67 68 69                  
*/
			retVal = 32;
			break;

		case __mosLinux_2_4:
		case __mosSolaris_8:
			_time64(&lTime);

			valD = (DWORD) (lTime & 0xFFFFFFFF);
			bbb = (BYTE*)&valD;
			dataIn[0] = bbb[0];
			dataIn[1] = bbb[1];
			dataIn[2] = bbb[2];
			dataIn[3] = bbb[3];

			valD = GetTickCount();
			bbb = (BYTE*)&valD;
			dataIn[4] = bbb[0];
			dataIn[5] = bbb[1];
			dataIn[6] = bbb[2];
			dataIn[7] = bbb[3];

			for(i=8; i<56; i++)
				dataIn[i] = (BYTE)i;
/* Linux 2.4.ceva
0020   -- -- -- -- -- -- -- -- -- -- 43 96 a8 19 00 03
0030   95 16 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15
0040   16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25
0050   26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35
0060   36 37                                          
*/
/* Solaris 5.8
0020   -- -- -- -- -- -- -- -- -- -- 43 95 86 45 00 0b
0030   b8 ca 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15
0040   16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25
0050   26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35
0060   36 37                                          
*/
			retVal = 56;
			break;

		case __mosLinux_2_6:
			_time64(&lTime);

			valD = (DWORD) (lTime & 0xFFFFFFFF);
			bbb = (BYTE*)&valD;
			dataIn[0] = bbb[3];
			dataIn[1] = bbb[2];
			dataIn[2] = bbb[1];
			dataIn[3] = bbb[0];

			valD = GetTickCount();
			bbb = (BYTE*)&valD;
			dataIn[4] = bbb[3];
			dataIn[5] = bbb[2];
			dataIn[6] = bbb[1];
			dataIn[7] = bbb[0];

			for(i=8; i<56; i++)
				dataIn[i] = (BYTE)i;
/* Linux 2.6.ceva
0020   -- -- -- -- -- -- -- -- -- -- e2 86 95 43 2c 30
0030   00 00 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15
0040   16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25
0050   26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35
0060   36 37                                          
*/
			retVal = 56;
			break;

		case __mosNevada35 :
			_time64(&lTime);

			valD = (DWORD) (lTime & 0xFFFFFFFF);
			bbb = (BYTE*)&valD;
			dataIn[0] = bbb[3];
			dataIn[1] = bbb[2];
			dataIn[2] = bbb[1];
			dataIn[3] = bbb[0];

			valD = GetTickCount();
			bbb = (BYTE*)&valD;
			dataIn[4] = bbb[3];
			dataIn[5] = bbb[2];
			dataIn[6] = bbb[1];
			dataIn[7] = bbb[0];

			for(i=8; i<56; i++)
				dataIn[i] = (BYTE)i;

			retVal = 56;
			break;

		default:
			memset(dataIn, 0, 56);
			retVal = 56;
			break;
	}

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::AddrToDnsReqAddr(BYTE* buff, DWORD addrIn)
{
	in_addr ia;
	char convBuff[34];
	BYTE len;
	int idx;
	errno_t err;

	if(buff==NULL) return false;

	ia.S_un.S_addr = addrIn;

	idx = 0;

	memset(&convBuff[0], 0, 34);
	convBuff[0]='9';
	err = _itoa_s((unsigned int)ia.S_un.S_un_b.s_b4, &convBuff[1], 33, 10);
	if(err!=0) return false;
	len = (BYTE)strlen(convBuff);
	convBuff[0] = len - 1;
	memcpy(&buff[idx], &convBuff[0], len);
	idx += len;

	memset(&convBuff[0], 0, 34);
	convBuff[0]='9';
	err = _itoa_s((unsigned int)ia.S_un.S_un_b.s_b3, &convBuff[1], 33, 10);
	if(err!=0) return false;
	len = (BYTE)strlen(convBuff);
	convBuff[0] = len - 1;
	memcpy(&buff[idx], &convBuff[0], len);
	idx += len;

	memset(&convBuff[0], 0, 34);
	convBuff[0]='9';
	err = _itoa_s((unsigned int)ia.S_un.S_un_b.s_b2, &convBuff[1], 33, 10);
	if(err!=0) return false;
	len = (BYTE)strlen(convBuff);
	convBuff[0] = len - 1;
	memcpy(&buff[idx], &convBuff[0], len);
	idx += len;

	memset(&convBuff[0], 0, 34);
	convBuff[0]='9';
	err = _itoa_s((unsigned int)ia.S_un.S_un_b.s_b1, &convBuff[1], 33, 10);
	if(err!=0) return false;
	len = (BYTE)strlen(convBuff);
	convBuff[0] = len - 1;
	memcpy(&buff[idx], &convBuff[0], len);

	return true;
}

bool PacketBuilderEx::AddrToDnsReqAddr6(BYTE* buff, in_addr6 *addrIn)
{
	BYTE bbh, bbl;
	int idx;

	if(buff==NULL) return false;
	if(addrIn==NULL) return false;

	for(idx=0; idx<16; idx++){
		bbl = addrIn->u.Byte[15 - idx];
		bbh = bbl >> 4;

		buff[4*idx]     = 0x01;
		buff[4*idx + 1] = LastSignifiantDigitToHexChar(bbl);
		buff[4*idx + 2] = 0x01;
		buff[4*idx + 3] = LastSignifiantDigitToHexChar(bbh);
	}

	return true;
}

char PacketBuilderEx::LastSignifiantDigitToHexChar(BYTE bbbIn)
{
	BYTE bbb;

	bbb = bbbIn & 0x0F;

	if(bbb<10)
		return (char)('0' + bbb);

	return (char)('a' - 10 + bbb);
}

bool PacketBuilderEx::NameToDnsReqName(BYTE* nameIn, DWORD sizeIn, BYTE* nameOut, DWORD sizeOut)
{
	if(nameIn==NULL) return false;
	if(nameOut==NULL) return false;
	if(sizeIn>(sizeOut-2)) return false;

	DWORD idx, oIdx;
	int pLen;

	pLen = 0;
	oIdx = 0;
	for(idx=0; idx<sizeIn; idx++){
		if(nameIn[idx]!='.'){
			pLen++;
		}
		else{
			if(pLen<1 || pLen>255) return false;
			nameOut[oIdx] = (BYTE)pLen;
			oIdx++;
			memcpy(&nameOut[oIdx], &nameIn[idx-pLen], pLen);
			oIdx += pLen;
			pLen = 0;
		}
	}

	if(pLen>0){
		if(pLen>255) return false;
		nameOut[oIdx] = (BYTE)pLen;
		oIdx++;
		memcpy(&nameOut[oIdx], &nameIn[idx-pLen], pLen);
	}

	return true;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackTcpSyn(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wDP,					// destination port
			DWORD dwSeq					// sequence
		)
{
	bool retVal;
	BYTE optBuff[20];
	int optBuffSize;

	optBuffSize = BuildSynOptions(&optBuff[0]);

	mimicInfoPack.GetNewSet(&mimicInfo, __miipTcp);

	retVal = BuildPacketTCP(
				dwSA, dwDA,
				mimicInfo.srcPort, wDP,
				mimicInfo.bTosTcp, mimicInfo.wIpIdTcp, mimicInfo.wFragOffTcp, mimicInfo.bTTLTcp,
				dwSeq, 0x00000000, TH_SYN, mimicInfo.wWindow, 0x0000,
				optBuff, (DWORD)optBuffSize,
				NULL, 0);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackTcpSynWithSrcPort(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wSP, WORD wDP,			// source and destination port
			DWORD dwSeq					// sequence
		)
{
	bool retVal;
	BYTE optBuff[20];
	int optBuffSize;

	optBuffSize = BuildSynOptions(&optBuff[0]);

	mimicInfoPack.GetNewSet(&mimicInfo, __miipTcp);

	retVal = BuildPacketTCP(
				dwSA, dwDA,
				wSP, wDP,
				mimicInfo.bTosTcp, mimicInfo.wIpIdTcp, mimicInfo.wFragOffTcp, mimicInfo.bTTLTcp,
				dwSeq, 0x00000000, TH_SYN, mimicInfo.wWindow, 0x0000,
				optBuff, (DWORD)optBuffSize,
				NULL, 0);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackTcpFlat(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD  wDP,					// destination port
			DWORD dwSeq,				// TCP sequence
			DWORD dwAck,				// TCP acknowledge
			BYTE  bFlags				// TCP flags
		)
{
	bool retVal;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipTcp);

	retVal = BuildPacketTCP(
				dwSA, dwDA,
				mimicInfo.srcPort, wDP,
				mimicInfo.bTosTcp, mimicInfo.wIpIdTcp, mimicInfo.wFragOffTcp, mimicInfo.bTTLTcp,
				dwSeq, dwAck, bFlags, mimicInfo.wWindow, 0x0000,
				NULL, 0,
				NULL, 0);

	return retVal;
}

bool PacketBuilderEx::BuildPackTcpFlatWithSrcPort(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD  wSP,					// source port
			WORD  wDP,					// destination port
			DWORD dwSeq,				// TCP sequence
			DWORD dwAck,				// TCP acknowledge
			BYTE  bFlags				// TCP flags
		)
{
	bool retVal;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipTcp);

	retVal = BuildPacketTCP(
				dwSA, dwDA,
				wSP, wDP,
				mimicInfo.bTosTcp, mimicInfo.wIpIdTcp, mimicInfo.wFragOffTcp, mimicInfo.bTTLTcp,
				dwSeq, dwAck, bFlags, mimicInfo.wWindow, 0x0000,
				NULL, 0,
				NULL, 0);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackIcmpEchoRequest(DWORD dwSA, DWORD dwDA)
{
	BYTE buff[56];
	bool retVal;
	int buffSize;

	buffSize = BuildIcmpEchoDataBuffer(&buff[0]);
	
	mimicInfoPack.GetNewSet(&mimicInfo, __miipIcmp);

	retVal = BuildPacketICMP(dwSA, dwDA,
				mimicInfo.bTosIcmp, mimicInfo.wIpIdIcmp, mimicInfo.wFragOffIcmp, mimicInfo.bTTLIcmp,
				0x08, 0x00, mimicInfo.wIcmpId, mimicInfo.wIcmpSeq,
				&buff[0], (DWORD)buffSize);

	return retVal;
}

bool PacketBuilderEx::BuildPackIcmpEchoRequestWithId(DWORD dwSA, DWORD dwDA, WORD wIcmpId)
{
	BYTE buff[56];
	bool retVal;
	int buffSize;

	buffSize = BuildIcmpEchoDataBuffer(&buff[0]);
	
	mimicInfoPack.GetNewSet(&mimicInfo, __miipIcmp);

	retVal = BuildPacketICMP(dwSA, dwDA,
				mimicInfo.bTosIcmp, mimicInfo.wIpIdIcmp, mimicInfo.wFragOffIcmp, mimicInfo.bTTLIcmp,
				0x08, 0x00, wIcmpId, mimicInfo.wIcmpSeq,
				&buff[0], (DWORD)buffSize);

	return retVal;
}

bool PacketBuilderEx::BuildPackIcmpEchoRequestWithUserData(DWORD dwSA, DWORD dwDA, BYTE* dataIn, int sizeIn)
{
	bool retVal;

	if(dataIn==NULL && sizeIn!=0) return false;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipIcmp);

	retVal = BuildPacketICMP(dwSA, dwDA,
				mimicInfo.bTosIcmp, mimicInfo.wIpIdIcmp, mimicInfo.wFragOffIcmp, mimicInfo.bTTLIcmp,
				0x08, 0x00, mimicInfo.wIcmpId, mimicInfo.wIcmpSeq,
				dataIn, (DWORD)sizeIn);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackEmptyIpProto(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			BYTE bProtocol				// protocol
	)
{
	bool retVal;

	switch(bProtocol){
		case IPPROTO_ICMP :
			mimicInfoPack.GetNewSet(&mimicInfo, __miipIcmp);
			retVal = BuildPacketEmptyIpProto(dwSA, dwDA, mimicInfo.bTosIcmp, mimicInfo.wIpIdIcmp, mimicInfo.wFragOffIcmp, mimicInfo.bTTLIcmp, bProtocol);
			break;

		case IPPROTO_TCP :
			mimicInfoPack.GetNewSet(&mimicInfo, __miipTcp);
			retVal = BuildPacketEmptyIpProto(dwSA, dwDA, mimicInfo.bTosTcp, mimicInfo.wIpIdTcp, mimicInfo.wFragOffTcp, mimicInfo.bTTLTcp, bProtocol);
			break;

		case IPPROTO_UDP :
			mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);
			retVal = BuildPacketEmptyIpProto(dwSA, dwDA, mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp, bProtocol);
			break;

		default :
			// TODO What the fuck do I have to put here ?
			// TODO What the fuck do I have to put here ?
			// TODO What the fuck do I have to put here ?
			mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);
			retVal = BuildPacketEmptyIpProto(dwSA, dwDA, mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp, bProtocol);
			break;
	}


	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackUDPFlat(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wDstPort				// destination port
		)
{
	bool retVal;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	retVal = BuildPacketUDP(dwSA, dwDA,
				mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp,
				mimicInfo.srcPort, wDstPort,
				NULL, 0);

	return retVal;
}

bool PacketBuilderEx::BuildPackUDPWithUserData(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wDstPort,				// destination port
			BYTE* dataIn,				// payload
			int sizeIn					// payload's size
		)
{
	bool retVal;

	if(dataIn==NULL && sizeIn!=0) return false;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	retVal = BuildPacketUDP(dwSA, dwDA,
				mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp,
				mimicInfo.srcPort, wDstPort,
				dataIn, (DWORD)sizeIn);

	return retVal;
}

bool PacketBuilderEx::BuildPackUDPWithUserDataAndPort(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wSrcPort,				// source port
			WORD wDstPort,				// destination port
			BYTE* dataIn,				// payload
			int sizeIn					// payload's size
		)
{
	bool retVal;

	if(dataIn==NULL && sizeIn!=0) return false;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	retVal = BuildPacketUDP(dwSA, dwDA,
				mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp,
				wSrcPort, wDstPort,
				dataIn, (DWORD)sizeIn);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackDNSQueryRRPTR(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			DWORD rrAddr				// request address
		)
{
	DNSRequestHeader dnsReqHdr;
	char nameBuff[17];
	int reqSize;
	int idx;
	BYTE *buff;
	bool retVal;

	memset(&nameBuff[0], 0, 17);
	if(!AddrToDnsReqAddr((BYTE*)&nameBuff[0], rrAddr))
		return false;

	reqSize  = sizeof(DNSRequestHeader);
	reqSize += (int)strlen(nameBuff);
	reqSize += 14;	// '07'in-addr'04'arpa'00'
	reqSize += 4;	// type and class

	try{
		buff = new BYTE[reqSize];
	}
	catch(...){
		buff = NULL;
	}
	if(buff==NULL) return false;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	dnsReqHdr.transactionId = htons(mimicInfo.wTransId);
	dnsReqHdr.flags         = htons(0x0100);
	dnsReqHdr.questions     = htons(0x0001);
	dnsReqHdr.answerRR      = 0x0000;
	dnsReqHdr.authorityRR   = 0x0000;
	dnsReqHdr.additionalRR  = 0x0000;

	memcpy(&buff[0], &dnsReqHdr, sizeof(DNSRequestHeader));
	idx = sizeof(DNSRequestHeader);

	memcpy(&buff[idx], &nameBuff[0], strlen(nameBuff));
	idx += (int)strlen(nameBuff);

	buff[idx]      = 0x07;
	buff[idx + 1]  = 'i';
	buff[idx + 2]  = 'n';
	buff[idx + 3]  = '-';
	buff[idx + 4]  = 'a';
	buff[idx + 5]  = 'd';
	buff[idx + 6]  = 'd';
	buff[idx + 7]  = 'r';
	buff[idx + 8]  = 0x04;
	buff[idx + 9]  = 'a';
	buff[idx + 10] = 'r';
	buff[idx + 11] = 'p';
	buff[idx + 12] = 'a';
	buff[idx + 13] = 0x00;

	buff[idx + 14] = 0x00;
	buff[idx + 15] = 0x0C;
	buff[idx + 16] = 0x00;
	buff[idx + 17] = 0x01;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	retVal = BuildPacketUDP(dwSA, dwDA,
				mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp,
				mimicInfo.srcPort, 53,
				buff, (DWORD)reqSize);

	delete[] buff;

	return retVal;
}

bool PacketBuilderEx::BuildPackDNSQueryRRPTR6(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			in_addr6 *rrAddr				// request address
		)
{
	DNSRequestHeader dnsReqHdr;
	char nameBuff[64];
	int reqSize;
	int idx;
	BYTE *buff;
	bool retVal;

//	memset(&nameBuff[0], 0, 64); // not needed, entire buffer will be filled

	if(!AddrToDnsReqAddr6((BYTE*)&nameBuff[0], rrAddr))
		return false;

	reqSize  = sizeof(DNSRequestHeader);
	reqSize += 64;	// length of name buffer
	reqSize += 10;	// '03'ip6'04'arpa'00'
	reqSize += 4;	// type and class

	try{
		buff = new BYTE[reqSize];
	}
	catch(...){
		buff = NULL;
	}
	if(buff==NULL) return false;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	dnsReqHdr.transactionId = htons(mimicInfo.wTransId);
	dnsReqHdr.flags         = htons(0x0100);
	dnsReqHdr.questions     = htons(0x0001);
	dnsReqHdr.answerRR      = 0x0000;
	dnsReqHdr.authorityRR   = 0x0000;
	dnsReqHdr.additionalRR  = 0x0000;

	memcpy(&buff[0], &dnsReqHdr, sizeof(DNSRequestHeader));
	idx = sizeof(DNSRequestHeader);

	memcpy(&buff[idx], &nameBuff[0], 64);
	idx += 64;

	buff[idx]     = 0x03;
	buff[idx + 1] = 'i';
	buff[idx + 2] = 'p';
	buff[idx + 3] = '6';
	buff[idx + 4] = 0x04;
	buff[idx + 5] = 'a';
	buff[idx + 6] = 'r';
	buff[idx + 7] = 'p';
	buff[idx + 8] = 'a';
	buff[idx + 9] = 0x00;

	buff[idx + 10] = 0x00;
	buff[idx + 11] = 0x0C;
	buff[idx + 12] = 0x00;
	buff[idx + 13] = 0x01;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	retVal = BuildPacketUDP(dwSA, dwDA,
				mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp,
				mimicInfo.srcPort, 53,
				buff, (DWORD)reqSize);

	delete[] buff;

	return retVal;
}

bool PacketBuilderEx::BuildPackDNSQueryMX(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			BYTE* rrAddr,				// request address
			DWORD rrAddrLen				// request address length
		)
{
	DNSRequestHeader dnsReqHdr;
	char nameBuff[1024];
	int reqSize;
	int idx;
	BYTE *buff;
	bool retVal;

	memset(&nameBuff[0], 0, 1024);
	if(!NameToDnsReqName(rrAddr, rrAddrLen, (BYTE*)nameBuff, 1024))
		return false;

	reqSize  = sizeof(DNSRequestHeader);
	reqSize += rrAddrLen + 2;
	reqSize += 4;	// type and class

	try{
		buff = new BYTE[reqSize];
	}
	catch(...){
		buff = NULL;
	}
	if(buff==NULL) return false;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipUdp);

	dnsReqHdr.transactionId = htons(mimicInfo.wTransId);
	dnsReqHdr.flags         = htons(0x0100);
	dnsReqHdr.questions     = htons(0x0001);
	dnsReqHdr.answerRR      = 0x0000;
	dnsReqHdr.authorityRR   = 0x0000;
	dnsReqHdr.additionalRR  = 0x0000;

	memcpy(&buff[0], &dnsReqHdr, sizeof(DNSRequestHeader));
	idx = sizeof(DNSRequestHeader);

	memcpy(&buff[idx], &nameBuff[0], rrAddrLen + 2);
	idx += (int)(rrAddrLen + 2);

	buff[idx + 0] = 0x00;
	buff[idx + 1] = 0x0F;
	buff[idx + 2] = 0x00;
	buff[idx + 3] = 0x01;

	retVal = BuildPacketUDP(dwSA, dwDA,
				mimicInfo.bTosUdp, mimicInfo.wIpIdUdp, mimicInfo.wFragOffUdp, mimicInfo.bTTLUdp,
				mimicInfo.srcPort, 53,
				buff, (DWORD)reqSize);

	delete[] buff;

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPacketArpRequest(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstIpIn[4]
		)
{
	return BuildPacketARP(1,
				srcMacIn, srcMacIn, srcIpIn,
				ethFF, eth00, dstIpIn
			);
}

bool PacketBuilderEx::BuildPacketArpReply(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstMacIn[6],
			BYTE dstIpIn[4]
		)
{
	return BuildPacketARP(2,
				srcMacIn, srcMacIn, srcIpIn,
				dstMacIn, dstMacIn, dstIpIn
			);
}

bool PacketBuilderEx::BuildPacketArpGratuitous(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4]
		)
{
	return BuildPacketARP(1,
				srcMacIn, srcMacIn, srcIpIn,
				ethFF, eth00, srcIpIn
			);
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPacketArpRequestDotQ(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstIpIn[4],
			BYTE priorityIn,
			WORD vlanIdIn
		)
{
	return BuildPacketARPDotQ(1,
				srcMacIn, srcMacIn, srcIpIn,
				ethFF, eth00, dstIpIn,
				priorityIn, vlanIdIn
			);
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPackWolUdp(
			BYTE srcMacIn[6],
			BYTE dstMacIn[6],
			DWORD dwSA,
			DWORD dwDA,
			WORD wDstPort,				// default port is 7 (Depicus), 9 (NetScanTools) or 40000 (ahh.sourceforge.net/wol)
			BYTE wolMacIn[6]
		)
{
	BYTE wolPacket[102];
	bool res;
	int i;

	memset(&wolPacket[0], 0xFF, 6);
	for(i=0; i<16; i++)
		memcpy(&wolPacket[6*(i+1)], &wolMacIn[0], 6);

	res = BuildPackUDPWithUserData(dwSA, dwDA, wDstPort, &wolPacket[0], 102);
	if(!res) return false;

	res = AddEthernetHeader(srcMacIn, dstMacIn, 0x0800);
	return res;
}

bool PacketBuilderEx::BuildPackWolIcmp(
			BYTE srcMacIn[6],
			BYTE dstMacIn[6],
			DWORD dwSA,
			DWORD dwDA,
			BYTE wolMacIn[6]
		)
{
	BYTE wolPacket[102];
	bool res;
	int i;

	memset(&wolPacket[0], 0xFF, 6);
	for(i=0; i<16; i++)
		memcpy(&wolPacket[6*(i+1)], &wolMacIn[0], 6);

	res = BuildPackIcmpEchoRequestWithUserData(dwSA, dwDA, &wolPacket[0], 102);
	if(!res) return false;

	res = AddEthernetHeader(srcMacIn, dstMacIn, 0x0800);
	return res;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPacketDHCPDiscover(
			BYTE srcMacIn[6],
			DWORD reqIpIn,
			CString srcNameIn,
			DWORD transactionIdIn
		)
{
	DHCPMessage msg;
	MimicOS myMimic;
	int idx;

	msg.op     = 1;
	msg.hType  = 1;
	msg.hLen   = 6;
	msg.hops   = 0;
	msg.xid    = transactionIdIn;
	msg.secs   = 0;
	msg.flags  = 0;
	msg.ciAddr = 0;
	msg.yiAddr = 0;
	msg.siAddr = 0;
	msg.giAddr = 0;

	memset(msg.chAddr, 0, 16);
	memcpy(msg.chAddr, srcMacIn, 6);

	memset(msg.sName, 0, 64);
	memset(msg.file,  0, 128);

	// The options
	memset(msg.options, 0, 312);

	myMimic = mimicInfoPack.GetMimic();

	idx = packetBuilderDhcp.DhcpAddDiscoverOptions(myMimic, &msg.options[0], srcMacIn, reqIpIn, srcNameIn);
	if(idx>312) return false;
	idx += 236;

	return BuildPackUDPWithUserDataAndPort(0x00000000, 0xFFFFFFFF, 68, 67, (BYTE*)&msg, idx);
}

bool PacketBuilderEx::BuildPacketDHCPRequest(
			BYTE srcMacIn[6],
			DWORD srvIpIn,
			DWORD reqIpIn,
			CString srcNameIn,
			DWORD transactionIdIn,
			DWORD leaseTimeIn
		)
{
	DWORD leaseTime;
	DHCPMessage msg;
	MimicOS myMimic;
	int idx;

	msg.op     = 1;
	msg.hType  = 1;
	msg.hLen   = 6;
	msg.hops   = 0;
	msg.xid    = transactionIdIn;
	msg.secs   = 0;
	msg.flags  = 0;
	msg.ciAddr = 0;
	msg.yiAddr = 0;
	msg.siAddr = 0;
	msg.giAddr = 0;

	memset(msg.chAddr, 0, 16);
	memcpy(msg.chAddr, srcMacIn, 6);

	memset(msg.sName, 0, 64);
	memset(msg.file,  0, 128);

	// The options
	memset(msg.options, 0, 312);

	myMimic = mimicInfoPack.GetMimic();

	if(leaseTimeIn==0) leaseTime = 0x000A8C00;		// 8 days
	else               leaseTime = leaseTimeIn;

	idx = packetBuilderDhcp.DhcpAddRequestOptions(myMimic, &msg.options[0], srcMacIn, srvIpIn, reqIpIn, srcNameIn, leaseTime);
	if(idx>312) return false;
	idx += 236;

	return BuildPackUDPWithUserDataAndPort(0x00000000, 0xFFFFFFFF, 68, 67, (BYTE*)&msg, idx);
}

//---------------------------------------------------------------------------

bool PacketBuilderEx::BuildPacketIGMPQueryGeneral(DWORD dwSA, BYTE version)
{
	BYTE groupAddress[4];
	in_addr ia;

	ia.S_un.S_un_b.s_b1 = 224;
	ia.S_un.S_un_b.s_b2 = 0;
	ia.S_un.S_un_b.s_b3 = 0;
	ia.S_un.S_un_b.s_b4 = 1;

	groupAddress[0] = 0;
	groupAddress[1] = 0;
	groupAddress[2] = 0;
	groupAddress[3] = 0;

	return BuildPacketIGMPQuerySpecific(dwSA, ia.S_un.S_addr, version, &groupAddress[0]);
}

bool PacketBuilderEx::BuildPacketIGMPQuerySpecific(DWORD dwSA, DWORD dwDA, BYTE version, BYTE groupAddress[4])
{
	bool retVal;
	BYTE bTOSigmp;

	mimicInfoPack.GetNewSet(&mimicInfo, __miipIgmp);

	// TODO bTTL, bTOS, wID si bFragOff sunt chiar asa la toate ??? Daca le schimbi schimba si la mimicInfoPack.GetNewSet !

	// according to the RFC3376, an IGMPv3 query should have the TOS set to 0xC0 (Internetwork Control)
	if(version==3) bTOSigmp = 0xC0;
	else           bTOSigmp = 0x00;

	// according to the RFC3376 and RFC2236, bTTL is set to 1

	retVal = BuildPacketIGMPQuery(
				dwSA, dwDA,
				bTOSigmp, 0x0000, IPH_FLAG_DF, 0x01,
				version,
				mimicInfo.bMaxResponseTime, groupAddress);

	return retVal;
}

BYTE PacketBuilderEx::GetIgmpMaxResponseTime(void)
{
	return mimicInfoPack.GetIgmpMaxResponseTime();
}

//---------------------------------------------------------------------------
